home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / glibc108.zip / glibc108 / stdio / printf-prs.c < prev    next >
C/C++ Source or Header  |  1992-03-23  |  4KB  |  208 lines

  1. /* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3.  
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public License as
  6. published by the Free Software Foundation; either version 2 of the
  7. License, or (at your option) any later version.
  8.  
  9. The GNU C Library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. Library General Public License for more details.
  13.  
  14. You should have received a copy of the GNU Library General Public
  15. License along with the GNU C Library; see the file COPYING.LIB.  If
  16. not, write to the Free Software Foundation, Inc., 675 Mass Ave,
  17. Cambridge, MA 02139, USA.  */
  18.  
  19. #include <ansidecl.h>
  20. #include <stdio.h>
  21. #include <printf.h>
  22. #include <limits.h>
  23. #include <string.h>
  24. #include <ctype.h>
  25.  
  26. #ifdef    __GNUC__
  27. #define    HAVE_LONGLONG
  28. #endif
  29.  
  30. extern printf_arginfo_function *__printf_arginfo_table[];
  31.  
  32. size_t
  33. DEFUN(parse_printf_format, (fmt, n, argtypes),
  34.       CONST char *fmt AND size_t n AND int *argtypes)
  35. {
  36.   register CONST char *f;
  37.   size_t need = 0;
  38.  
  39.   for (f = strchr (fmt, '%'); f != NULL; f = strchr (f, '%'))
  40.     {
  41.       struct printf_info info;
  42.       printf_arginfo_function *arginfo;
  43.  
  44.       ++f;
  45.  
  46.       info.space = info.showsign = info.left = info.alt = 0;
  47.       info.pad = ' ';
  48.       while (*f == ' ' || *f == '+' || *f == '-' || *f == '#' || *f == '0')
  49.     switch (*f++)
  50.       {
  51.       case ' ':
  52.         info.space = 1;
  53.         break;
  54.       case '+':
  55.         info.showsign = 1;
  56.         break;
  57.       case '-':
  58.         info.left = 1;
  59.         break;
  60.       case '#':
  61.         info.alt = 1;
  62.         break;
  63.       case '0':
  64.         info.pad = '0';
  65.         break;
  66.       }
  67.       if (info.left)
  68.     info.pad = ' ';
  69.  
  70.       /* Get the field width.  */
  71.       if (*f == '*')
  72.     {
  73.       if (++need < n)
  74.         *argtypes++ = PA_INT;
  75.       info.width = INT_MIN;
  76.       ++f;
  77.     }
  78.       else
  79.     {
  80.       info.width = 0;
  81.       while (isdigit(*f))
  82.         {
  83.           info.width *= 10;
  84.           info.width += *f++ - '0';
  85.         }
  86.     }
  87.  
  88.       /* Get the precision.  */
  89.       /* -1 means none given; 0 means explicit 0.  */
  90.       info.prec = -1;
  91.       if (*f == '.')
  92.     {
  93.       ++f;
  94.       if (*f == '*')
  95.         {
  96.           /* The precision is given in an argument.  */
  97.           if (++need < n)
  98.         *argtypes++ = PA_INT;
  99.           info.prec = INT_MIN;
  100.           ++f;
  101.         }
  102.       else if (isdigit(*f))
  103.         {
  104.           info.prec = 0;
  105.           while (*f != '\0' && isdigit(*f))
  106.         {
  107.           info.prec *= 10;
  108.           info.prec += *f++ - '0';
  109.         }
  110.         }
  111.     }
  112.  
  113.       /* Check for type modifiers.  */
  114.       info.is_short = info.is_long = info.is_long_double = 0;
  115.       while (*f == 'h' || *f == 'l' || *f == 'L')
  116.     switch (*f++)
  117.       {
  118.       case 'h':
  119.         /* int's are short int's.  */
  120.         info.is_short = 1;
  121.         break;
  122.       case 'l':
  123. #ifdef    HAVE_LONGLONG
  124.         if (info.is_long)
  125.           /* A double `l' is equivalent to an `L'.  */
  126.           info.is_long_double = 1;
  127.         else
  128. #endif
  129.           /* int's are long int's.  */
  130.           info.is_long = 1;
  131.         break;
  132.       case 'L':
  133.         /* double's are long double's, and int's are long long int's.  */
  134.         info.is_long_double = 1;
  135.         break;
  136.       }
  137.  
  138.       if (*f == '\0')
  139.     return need;
  140.  
  141.       info.spec = *f++;
  142.  
  143.       arginfo = __printf_arginfo_table[info.spec];
  144.       if (arginfo != NULL)
  145.     {
  146.       size_t nargs
  147.         = (*arginfo) (&info, need > n ? 0 : n - need, argtypes);
  148.       need += nargs;
  149.       argtypes += nargs;
  150.     }
  151.       else
  152.     {
  153.       int type;
  154.       switch (info.spec)
  155.         {
  156.         case 'i':
  157.         case 'd':
  158.         case 'u':
  159.         case 'o':
  160.         case 'X':
  161.         case 'x':
  162.           type = PA_INT;
  163.           break;
  164.  
  165.         case 'e':
  166.         case 'E':
  167.         case 'f':
  168.         case 'g':
  169.         case 'G':
  170.           type = PA_DOUBLE;
  171.           break;
  172.  
  173.         case 'c':
  174.           type = PA_CHAR;
  175.           break;
  176.  
  177.         case 's':
  178.           type = PA_STRING;
  179.           break;
  180.  
  181.         case 'p':
  182.           type = PA_POINTER;
  183.           break;
  184.  
  185.         case 'n':
  186.           type = PA_INT | PA_FLAG_PTR;
  187.           break;
  188.  
  189.         default:
  190.           /* No arg for an unknown spec.  */
  191.           continue;
  192.         }
  193.  
  194.       if (info.is_long_double)
  195.         type |= PA_FLAG_LONG_DOUBLE;
  196.       if (info.is_long)
  197.         type |= PA_FLAG_LONG;
  198.       if (info.is_short)
  199.         type |= PA_FLAG_SHORT;
  200.  
  201.       if (++need < n)
  202.         *argtypes++ = type;
  203.     }
  204.     }
  205.  
  206.   return need;
  207. }
  208.